<template>
    <div>
        <p>Vue 3 生命周期钩子详解</p>
        <p>Vue 3 组件的生命周期可以分为创建、挂载、更新和销毁四个主要阶段</p>
        <p>在 Composition API (setup) 中，生命周期钩子需要从 vue 中导入使用</p>
        <h2> {{ sum }}</h2>
        <button @click="changeSum">点击改变sum</button>
    </div>
</template>

<script lang="ts" setup>
/**
 * Vue 3 生命周期钩子详解
 * 
 * Vue 3 组件的生命周期可以分为创建、挂载、更新和销毁四个主要阶段
 * 在 Composition API (setup) 中，生命周期钩子需要从 vue 中导入使用
 * 
 * 导入方式：
 * import { 
 *   onBeforeMount, onMounted, onBeforeUpdate, onUpdated, 
 *   onBeforeUnmount, onUnmounted, onActivated, onDeactivated,
 *   onErrorCaptured, onRenderTracked, onRenderTriggered 
 * } from 'vue'
 * 
 * 1. 创建阶段
 * -------------
 * 
 * setup()
 * - 作用：组件创建前执行，是 Composition API 的入口
 * - 时机：在 beforeCreate 和 created 之前执行
 * - 使用场景：
 *   · 定义响应式数据
 *   · 定义方法
 *   · 使用组合式函数
 *   · 注册生命周期钩子
 * - 注意：此时组件实例尚未创建，无法访问 this
 * 
 * 2. 挂载阶段
 * -------------
 * 
 * onBeforeMount()
 * - 作用：组件挂载到 DOM 前调用
 * - 时机：模板编译完成，虚拟 DOM 创建完成，但尚未挂载到实际 DOM
 * - 使用场景：
 *   · 需要访问渲染前的 DOM 状态
 *   · 最后一次修改响应式数据而不触发重新渲染
 * - 示例：
 *   onBeforeMount(() => {
 *     console.log('组件即将挂载')
 *   })
 * 
 * onMounted()
 * - 作用：组件挂载到 DOM 后调用
 * - 时机：组件已挂载到实际 DOM，可以访问 DOM 元素
 * - 使用场景：
 *   · 初始化需要访问 DOM 的库（如图表、地图等）
 *   · 发送初始化数据请求
 *   · 添加事件监听器
 *   · 设置定时器
 *   · DOM 操作
 * - 示例：
 *   onMounted(() => {
 *     // 可以访问 DOM 元素
 *     const element = document.getElementById('my-element')
 *     // 发起数据请求
 *     fetchData()
 *   })
 * 
 * 3. 更新阶段
 * -------------
 * 
 * onBeforeUpdate()
 * - 作用：组件更新前调用
 * - 时机：响应式数据更新，但 DOM 尚未重新渲染
 * - 使用场景：
 *   · 在 DOM 更新前访问现有的 DOM 状态
 *   · 手动清除已添加的事件监听器
 * - 示例：
 *   onBeforeUpdate(() => {
 *     // 获取更新前的 DOM 状态
 *     const currentScrollPosition = element.scrollTop
 *   })
 * 
 * onUpdated()
 * - 作用：组件更新后调用
 * - 时机：响应式数据导致的 DOM 更新完成后
 * - 使用场景：
 *   · 访问更新后的 DOM
 *   · 根据新 DOM 状态执行操作
 * - 注意：避免在此钩子中修改响应式数据，可能导致无限更新循环
 * - 示例：
 *   onUpdated(() => {
 *     // 访问更新后的 DOM
 *     console.log('DOM 已更新')
 *   })
 * 
 * 4. 销毁阶段
 * -------------
 * 
 * onBeforeUnmount()
 * - 作用：组件卸载前调用
 * - 时机：组件实例仍然完全正常工作
 * - 使用场景：
 *   · 清理定时器
 *   · 取消网络请求
 *   · 移除手动添加的事件监听器
 * - 示例：
 *   onBeforeUnmount(() => {
 *     // 清理工作
 *     clearInterval(timer)
 *     window.removeEventListener('resize', handleResize)
 *   })
 * 
 * onUnmounted()
 * - 作用：组件卸载后调用
 * - 时机：组件实例已被卸载，所有子组件也已被卸载
 * - 使用场景：
 *   · 最终清理工作
 *   · 通知服务器组件已销毁
 * - 示例：
 *   onUnmounted(() => {
 *     console.log('组件已卸载')
 *   })
 * 
 * 5. 特殊生命周期钩子
 * -------------------
 * 
 * onActivated()
 * - 作用：被 keep-alive 缓存的组件激活时调用
 * - 使用场景：
 *   · 恢复组件状态
 *   · 重新获取可能已过期的数据
 * - 示例：
 *   onActivated(() => {
 *     // 组件被激活
 *     refreshData()
 *   })
 * 
 * onDeactivated()
 * - 作用：被 keep-alive 缓存的组件停用时调用
 * - 使用场景：
 *   · 暂停消耗资源的任务
 *   · 保存当前状态
 * - 示例：
 *   onDeactivated(() => {
 *     // 组件被停用
 *     saveCurrentState()
 *   })
 * 
 * onErrorCaptured()
 * - 作用：捕获后代组件抛出的错误
 * - 使用场景：
 *   · 错误处理和日志记录
 *   · 向用户显示错误状态
 * - 示例：
 *   onErrorCaptured((err, instance, info) => {
 *     console.error(err)
 *     // 返回 false 可以阻止错误继续向上传播
 *     return false
 *   })
 * 
 * 6. 调试钩子（仅在开发模式可用）
 * ------------------------------
 * 
 * onRenderTracked()
 * - 作用：跟踪虚拟 DOM 重新渲染时的依赖
 * - 使用场景：调试组件的依赖关系
 * - 示例：
 *   onRenderTracked((event) => {
 *     console.log('依赖项触发了组件重新渲染', event)
 *   })
 * 
 * onRenderTriggered()
 * - 作用：跟踪触发虚拟 DOM 重新渲染的依赖
 * - 使用场景：确定哪个依赖项触发了重新渲染
 * - 示例：
 *   onRenderTriggered((event) => {
 *     console.log('由此依赖项触发的重新渲染', event)
 *   })
 * 
 * 7. 与 Options API 的对应关系
 * ---------------------------
 * 
 * Options API      |  Composition API
 * ----------------|------------------
 * beforeCreate    |  setup()
 * created         |  setup()
 * beforeMount     |  onBeforeMount
 * mounted         |  onMounted
 * beforeUpdate    |  onBeforeUpdate
 * updated         |  onUpdated
 * beforeUnmount   |  onBeforeUnmount
 * unmounted       |  onUnmounted
 * errorCaptured   |  onErrorCaptured
 * renderTracked   |  onRenderTracked
 * renderTriggered |  onRenderTriggered
 * activated       |  onActivated
 * deactivated     |  onDeactivated
 * 
 * 8. 生命周期钩子的执行顺序（父子组件）
 * ----------------------------------
 * 
 * 挂载过程：
 * 1. 父组件 setup()
 * 2. 父组件 onBeforeMount()
 * 3. 子组件 setup()
 * 4. 子组件 onBeforeMount()
 * 5. 子组件 onMounted()
 * 6. 父组件 onMounted()
 * 
 * 更新过程：
 * 1. 父组件 onBeforeUpdate()
 * 2. 子组件 onBeforeUpdate()
 * 3. 子组件 onUpdated()
 * 4. 父组件 onUpdated()
 * 
 * 卸载过程：
 * 1. 父组件 onBeforeUnmount()
 * 2. 子组件 onBeforeUnmount()
 * 3. 子组件 onUnmounted()
 * 4. 父组件 onUnmounted()
 * 
 * 9. 最佳实践
 * -----------
 * 
 * - 在 onMounted 中初始化数据和添加事件监听
 * - 在 onBeforeUnmount 中清理资源和事件监听
 * - 避免在 onUpdated 中修改响应式状态
 * - 使用 onErrorCaptured 进行错误处理
 * - 对于需要在组件激活/停用时处理的逻辑，使用 onActivated/onDeactivated
 */

 import { ref, onMounted, onBeforeUnmount, onUpdated, onBeforeMount,onBeforeUpdate,onUnmounted } from 'vue'

 const sum = ref(0)

 function changeSum() {
     sum.value += 1
 }

 onBeforeMount(() => {
     console.log('onBeforeMount 子-组件即将挂载')
 })

 onMounted(() => {
     console.log('onMounted 子-组件即将挂载')
 })
// 组件数据变化后调用
 onBeforeUpdate(() => {
     console.log('组件即将更新') 
 })
// 组件数据变化后调用
 onUpdated(() => {
     console.log('组件已更新')
 })
 onBeforeUnmount(() => {
     console.log('组件即将卸载') 
 })
 onUnmounted(() => {
     console.log('组件已卸载') 
 })
</script>

<style scoped>

</style>